package be.dch.util;

import java.lang.reflect.Array;

/**
 * <p>
 * Operations on arrays, primitive arrays (like <code>int[]</code>) and
 * primitive wrapper arrays (like <code>Integer[]</code>).
 * </p>
 * 
 * <p>
 * This class tries to handle <code>null</code> input gracefully. An exception
 * will not be thrown for a <code>null</code> array input. However, an Object
 * array that contains a <code>null</code> element may throw an exception. Each
 * method documents its behaviour.
 * </p>
 * 
 * <p>
 * #ThreadSafe#
 * </p>
 * 
 * @author Apache Software Foundation
 * @author Moritz Petersen
 * @author <a href="mailto:fredrik@westermarck.com">Fredrik Westermarck</a>
 * @author Nikolay Metchev
 * @author Matthew Hawthorne
 * @author Tim O'Brien
 * @author Pete Gieser
 * @author Gary Gregory
 * @author <a href="mailto:equinus100@hotmail.com">Ashwin S</a>
 * @author Maarten Coene
 * @since 2.0
 * @version $Id: ArrayUtils.java 1056988 2011-01-09 17:58:53Z niallp $
 */
@SuppressWarnings("rawtypes")
public final class ArrayUtils {

    private ArrayUtils() {
	// Utility class no constructors needed.
    }

    /**
     * <p>
     * Copies the given array and adds the given element at the end of the new
     * array.
     * </p>
     * 
     * <p>
     * The new array contains the same elements of the input array plus the
     * given element in the last position. The component type of the new array
     * is the same as that of the input array.
     * </p>
     * 
     * <p>
     * If the input array is <code>null</code>, a new one element array is
     * returned whose component type is the same as the element, unless the
     * element itself is null, in which case the return type is Object[]
     * </p>
     * 
     * <pre>
     * ArrayUtils.add(null, null)      = [null]
     * ArrayUtils.add(null, "a")       = ["a"]
     * ArrayUtils.add(["a"], null)     = ["a", null]
     * ArrayUtils.add(["a"], "b")      = ["a", "b"]
     * ArrayUtils.add(["a", "b"], "c") = ["a", "b", "c"]
     * </pre>
     * 
     * @param array
     *            the array to "add" the element to, may be <code>null</code>
     * @param element
     *            the object to add, may be <code>null</code>
     * @return A new array containing the existing elements plus the new element
     *         The returned array type will be that of the input array (unless
     *         null), in which case it will have the same type as the element.
     * @since 2.1
     */
    public static Object[] add(final Object[] array, final Object element) {
	Class type;
	if ((array == null) && (element == null)) {
	    type = Object.class;
	} else if (array == null) {
	    type = element.getClass();
	} else {
	    type = array.getClass();
	}
	final Object[] newArray = (Object[]) ArrayUtils.copyArrayGrow1(array, type);
	newArray[newArray.length - 1] = element;
	return newArray;
    }

    /**
     * Returns a copy of the given array of size 1 greater than the argument.
     * The last value of the array is left to the default value.
     * 
     * @param array
     *            The array to copy, must not be <code>null</code>.
     * @param newArrayType
     *            If <code>array</code> is <code>null</code>, create a size 1
     *            array of this type.
     * @return A new copy of the array of size 1 greater than the input.
     */
    private static Object copyArrayGrow1(final Object array, final Class newArrayType) {
	Object resultArray;
	if (array == null) {
	    resultArray = Array.newInstance(newArrayType, 1);
	} else {
	    final int arrayLength = Array.getLength(array);
	    final Object newArray = Array.newInstance(array.getClass().getComponentType(), arrayLength + 1);
	    System.arraycopy(array, 0, newArray, 0, arrayLength);
	    resultArray = newArray;
	}
	return resultArray;
    }

    /**
     * <p>
     * Checks if an array of Objects is empty or <code>null</code>.
     * </p>
     * 
     * @param array
     *            the array to test
     * @return <code>true</code> if the array is empty or <code>null</code>
     * @since 2.1
     */
    public static boolean isEmpty(final Object[] array) {
	return (array == null) || (array.length == 0);
    }
}
